package jp.dodododo.aop.interceptors;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import jp.dodododo.aop.annotation.Enhance;

import org.aopalliance.intercept.ConstructorInvocation;

/**
 * {@.en }
 * 
 * <br />
 * 
 * {@.ja }
 * 
 * @author Satoshi Kimura
 */
@Enhance(false)
public class SingletonInterceptor extends AbstractConstructorInterceptor {

	private static Map<Class<?>, Object> instances = Collections.synchronizedMap(new HashMap<Class<?>, Object>());

	public Object construct(ConstructorInvocation invocation) throws Throwable {
		Class<?> targetClass = getTargetClass(invocation);
		synchronized (targetClass) {
			if (instances.containsKey(targetClass)) {
				Object instance = instances.get(targetClass);
				copy(instance, invocation.getThis(), targetClass);
			} else {
				instances.put(targetClass, invocation.getThis());
				invocation.proceed();
			}
		}
		return null;
	}

	private void copy(Object src, Object dest, Class<?> clazz) throws IllegalArgumentException, IllegalAccessException {
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			if (Modifier.isFinal(field.getModifiers())) {
				continue;
			}
			field.setAccessible(true);
			field.set(dest, field.get(src));
		}
		Class<?> superclass = clazz.getSuperclass();
		if (superclass == null || superclass.equals(Object.class)) {
			return;
		} else {
			copy(src, dest, superclass);
		}
	}
}
